package fun.sanguo.controller;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.code.kaptcha.Producer;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import fun.sanguo.caches.UserCache;
import fun.sanguo.model.dto.DataInfo;
import fun.sanguo.model.dto.DataQuery;
import fun.sanguo.model.dto.ReqDto;
import fun.sanguo.model.dto.ResDto;
import fun.sanguo.model.dto.sys.*;
import fun.sanguo.model.enums.ResEnums;
import fun.sanguo.service.sys.SysUserService;
import fun.sanguo.service.sys.SysVersionService;
import fun.sanguo.utils.HttpUtils;
import fun.sanguo.utils.IdUtils;
import fun.sanguo.utils.RSAUtils;
import fun.sanguo.utils.exception.ArtificialException;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.util.List;

/**
 * Index接口，用于测试连通性及展示版本信息等
 *
 * @author ZYP
 * @date 2022-10-09
 */
@RestController
public class IndexController {

    protected Logger logger = LoggerFactory.getLogger(getClass());
    protected Logger sys_user_logger = LoggerFactory.getLogger("sys-user");

    @Resource
    SysVersionService sysVersionService;

    @Resource
    SysUserService sysUserService;

    @Resource(name = "captchaMath")
    private Producer captchaMath;

    /**
     * 系统默认接口，查询系统版本
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/")
    @ResponseBody
    public ResDto getLastVersion(HttpServletRequest request) {
        // 定义响应内容
        ResDto resDto = new ResDto();
        try {
            // 请求日志
            sys_user_logger.info("接受来自IP={}的访问请求", HttpUtils.getIpAddr(request));
            // 查询数据
            DataInfo<SysVersionResult> sysVersionResultDataInfo = sysVersionService.getLastVersion();
            // 封装响应
            resDto.setCode(ResEnums.SUCCESS.getCode());
            resDto.setMsg(ResEnums.SUCCESS.getMsg());
            resDto.setData(sysVersionResultDataInfo);
            // 响应日志
            sys_user_logger.info(resDto.toString());
        } catch (ArtificialException ae) {
            logger.error("查询系统版本过程中发生异常，exception={}", ae.getMsg());
            // 封装响应
            resDto.setCode(ae.getCode());
            resDto.setMsg(ae.getMsg());
        } catch (Exception e) {
            logger.error("查询系统版本过程中发生异常，exception={}", e.getMessage());
            // 封装响应
            resDto.setCode(ResEnums.EXCEPTION.getCode());
            resDto.setMsg(ResEnums.EXCEPTION.getMsg() + ": " + e.getMessage());
        }
        return resDto;
    }

    /**
     * 查询版本记录
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/release_history")
    @ResponseBody
    public ResDto getReleaseHistory(HttpServletRequest request) {
        // 定义响应内容
        ResDto resDto = new ResDto();
        try {
            // 请求日志
            sys_user_logger.info("接受来自IP={}的访问请求", HttpUtils.getIpAddr(request));
            // 查询数据
            DataInfo<List<SysVersionResult>> sysVersionResultListDataInfo = sysVersionService.getReleaseHistory();
            // 封装响应
            resDto.setCode(ResEnums.SUCCESS.getCode());
            resDto.setMsg(ResEnums.SUCCESS.getMsg());
            resDto.setData(sysVersionResultListDataInfo);
            // 响应日志
            sys_user_logger.info(resDto.toString());
        } catch (ArtificialException ae) {
            logger.error("查询版本记录过程中发生异常，exception={}", ae.getMsg());
            // 封装响应
            resDto.setCode(ae.getCode());
            resDto.setMsg(ae.getMsg());
        } catch (Exception e) {
            logger.error("查询版本记录过程中发生异常，exception={}", e.getMessage());
            // 封装响应
            resDto.setCode(ResEnums.EXCEPTION.getCode());
            resDto.setMsg(ResEnums.EXCEPTION.getMsg() + ": " + e.getMessage());
        }
        return resDto;
    }

    /**
     * 取短信验证码
     *
     * @param reqDto
     * @param request
     * @return
     */
    @RequestMapping(value = "/getSmsCaptcha")
    @ResponseBody
    public ResDto getSmsCaptcha(@RequestBody ReqDto reqDto, HttpServletRequest request) {
        // 定义响应内容
        ResDto resDto = new ResDto();
        try {
            // 请求日志
            sys_user_logger.info("接受来自IP={}的取短信验证码请求", HttpUtils.getIpAddr(request));
            // 获取请求包体
            DataQuery<SysUserLogonParam> sysUserLogonParamDataQuery = (DataQuery<SysUserLogonParam>) reqDto.getData();
            // 转换参数
            SysUserLogonParam sysUserLogonParam = new ObjectMapper().convertValue(sysUserLogonParamDataQuery.getParam(), SysUserLogonParam.class);
            // 获取手机号码
            String mobile = sysUserLogonParam.getMobile();
            // 判断手机号码为空、已有缓存
            if (StringUtils.isEmpty(mobile)) {
                // 参数错误
                resDto.setCode(ResEnums.ERR_PARAM.getCode());
                resDto.setMsg(ResEnums.ERR_PARAM.getMsg() + "，手机号码不能为空");
            } else if (StringUtils.isNotEmpty(UserCache.getSmsCaptcha(mobile))) {
                // 手机号码仍在有效期内
                resDto.setCode(ResEnums.ERR_PARAM.getCode());
                resDto.setMsg(ResEnums.ERR_PARAM.getMsg() + "，短信验证码仍在有效期");
            } else {
                // 生成随机六位数
                String smsCaptcha = String.valueOf(RandomUtils.nextInt(100000, 999999));
                // 发送短信
                // TODO
                // 放入缓存
                UserCache.putSmsCaptcha(mobile, smsCaptcha);
                // TODO 暂时回显到前端
                // 结果数据
                DataInfo<JSONObject> dataInfo = new DataInfo<>(new JSONObject());
                dataInfo.getData().put("smsCaptcha", smsCaptcha);
                // 封装响应
                resDto.setCode(ResEnums.SUCCESS.getCode());
                resDto.setMsg(ResEnums.SUCCESS.getMsg());
                resDto.setData(dataInfo);
            }
            // 响应日志
            sys_user_logger.info(resDto.toString());
        } catch (Exception e) {
            logger.error("获取短信验证码过程中发生异常，exception={}", e.getMessage());
            // 封装响应
            resDto.setCode(ResEnums.EXCEPTION.getCode());
            resDto.setMsg(ResEnums.EXCEPTION.getMsg() + ": " + e.getMessage());
        }
        return resDto;
    }

    /**
     * 取验证码
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/getCaptcha")
    @ResponseBody
    public ResDto getCaptcha(HttpServletRequest request) {
        // 定义响应内容
        ResDto resDto = new ResDto();
        try {
            // 请求日志
            sys_user_logger.info("接受来自IP={}的取验证码请求", HttpUtils.getIpAddr(request));
            // 生成登陆序列号（直接使用long会导致前端取值错误）
            String loginSeq = String.valueOf(new IdUtils().nextId());
            // 生成数学表达式验证码文本
            String capText = captchaMath.createText();
            // 截取表达式与结果
            String capStr = capText.substring(0, capText.lastIndexOf('@'));
            String result = capText.substring(capText.lastIndexOf('@') + 1);
            // 将验证码信息放入缓存中
            UserCache.putCaptcha(loginSeq, result);
            // 生成验证码图片
            BufferedImage image = captchaMath.createImage(capStr);
            // 写出到字节流
            FastByteArrayOutputStream fastByteArrayOutputStream = new FastByteArrayOutputStream();
            try {
                ImageIO.write(image, "png", fastByteArrayOutputStream);
            } catch (Exception e) {
                logger.error("生成验证码图片过程中发生异常，exception={}", e.getMessage());
            }
            // 结果数据
            DataInfo<JSONObject> dataInfo = new DataInfo<>(new JSONObject());
            dataInfo.getData().put("publicKey", RSAUtils.getPublicKey());
            dataInfo.getData().put("loginSeq", loginSeq);
            dataInfo.getData().put("image", fastByteArrayOutputStream.toByteArray());
            // 封装响应
            resDto.setCode(ResEnums.SUCCESS.getCode());
            resDto.setMsg(ResEnums.SUCCESS.getMsg());
            resDto.setData(dataInfo);
            // 响应日志
            sys_user_logger.info(resDto.toString());
        } catch (Exception e) {
            logger.error("获取验证码过程中发生异常，exception={}", e.getMessage());
            // 封装响应
            resDto.setCode(ResEnums.EXCEPTION.getCode());
            resDto.setMsg(ResEnums.EXCEPTION.getMsg() + ": " + e.getMessage());
        }
        return resDto;
    }

    /**
     * 处理用户注册请求
     *
     * @param reqDto
     * @param request
     * @return
     */
    @RequestMapping(value = "/logon")
    @ResponseBody
    public ResDto logon(@RequestBody ReqDto reqDto, HttpServletRequest request) {
        // 定义响应内容
        ResDto resDto = new ResDto();
        try {
            // 请求日志
            sys_user_logger.info("接受来自IP={}的注册请求", HttpUtils.getIpAddr(request));
            // 获取请求包体
            DataQuery<SysUserLogonParam> sysUserLogonParamDataQuery = (DataQuery<SysUserLogonParam>) reqDto.getData();
            // 业务处理
            DataInfo<SysUserLogonResult> sysUserLogonResult = sysUserService.logon(sysUserLogonParamDataQuery);
            // 封装响应
            resDto.setCode(ResEnums.SUCCESS.getCode());
            resDto.setMsg(ResEnums.SUCCESS.getMsg());
            resDto.setData(sysUserLogonResult);
            // 响应日志
            sys_user_logger.info(resDto.toString());
        } catch (ArtificialException ae) {
            logger.error("处理用户注册请求过程中发生异常，exception={}", ae.getMsg());
            // 封装响应
            resDto.setCode(ae.getCode());
            resDto.setMsg(ae.getMsg());
        } catch (Exception e) {
            logger.error("处理用户注册请求过程中发生异常，exception={}", e.getMessage());
            // 封装响应
            resDto.setCode(ResEnums.EXCEPTION.getCode());
            resDto.setMsg(ResEnums.EXCEPTION.getMsg() + ": " + e.getMessage());
        }
        return resDto;
    }

    /**
     * 处理用户登陆请求
     *
     * @param reqDto
     * @param request
     * @return
     */
    @RequestMapping(value = "/login")
    @ResponseBody
    public ResDto login(@RequestBody ReqDto reqDto, HttpServletRequest request) {
        // 定义响应内容
        ResDto resDto = new ResDto();
        try {
            // 请求日志
            sys_user_logger.info("接受来自IP={}的登陆请求", HttpUtils.getIpAddr(request));
            // 获取请求包体
            DataQuery<SysUserLoginParam> sysUserLoginParamDataQuery = (DataQuery<SysUserLoginParam>) reqDto.getData();
            // 业务处理
            DataInfo<SysUserLoginResult> sysUserLoginResult = sysUserService.login(sysUserLoginParamDataQuery);
            // 封装响应
            resDto.setCode(ResEnums.SUCCESS.getCode());
            resDto.setMsg(ResEnums.SUCCESS.getMsg());
            resDto.setData(sysUserLoginResult);
            // 响应日志
            sys_user_logger.info(resDto.toString());
        } catch (ArtificialException ae) {
            logger.error("处理用户登陆请求过程中发生异常，exception={}", ae.getMsg());
            // 封装响应
            resDto.setCode(ae.getCode());
            resDto.setMsg(ae.getMsg());
        } catch (Exception e) {
            logger.error("处理用户登陆请求过程中发生异常，exception={}", e.getMessage());
            // 封装响应
            resDto.setCode(ResEnums.EXCEPTION.getCode());
            resDto.setMsg(ResEnums.EXCEPTION.getMsg() + ": " + e.getMessage());
        }
        return resDto;
    }

    /**
     * 获取当前登陆用户信息
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/getCurrentUser")
    @ResponseBody
    public ResDto getCurrentUser(HttpServletRequest request) {
        // 定义响应内容
        ResDto resDto = new ResDto();
        try {
            // 请求日志
            sys_user_logger.info("接受来自IP={}的查询请求", HttpUtils.getIpAddr(request));
            // 获取当前登陆用户信息并封装响应
            resDto.setCode(ResEnums.SUCCESS.getCode());
            resDto.setMsg(ResEnums.SUCCESS.getMsg());
            resDto.setData(sysUserService.getCurrentUser());
            // 响应日志
            sys_user_logger.info(resDto.toString());
        } catch (ArtificialException ae) {
            logger.error("获取当前登陆用户信息过程中发生异常，exception={}", ae.getMsg());
            // 封装响应
            resDto.setCode(ae.getCode());
            resDto.setMsg(ae.getMsg());
        } catch (Exception e) {
            logger.error("获取当前登陆用户信息过程中发生异常，exception={}", e.getMessage());
            // 封装响应
            resDto.setCode(ResEnums.EXCEPTION.getCode());
            resDto.setMsg(ResEnums.EXCEPTION.getMsg() + ": " + e.getMessage());
        }
        return resDto;
    }

    /**
     * 处理用户注销请求
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/logout")
    @ResponseBody
    public ResDto logout(HttpServletRequest request) {
        // 定义响应内容
        ResDto resDto = new ResDto();
        try {
            // 请求日志
            sys_user_logger.info("接受来自IP={}的注销请求", HttpUtils.getIpAddr(request));
            // 业务处理
            StpUtil.logout();
            // 封装响应
            resDto.setCode(ResEnums.SUCCESS.getCode());
            resDto.setMsg(ResEnums.SUCCESS.getMsg());
            // 响应日志
            sys_user_logger.info(resDto.toString());
        } catch (Exception e) {
            logger.error("处理用户注销请求过程中发生异常，exception={}", e.getMessage());
            // 封装响应
            resDto.setCode(ResEnums.EXCEPTION.getCode());
            resDto.setMsg(ResEnums.EXCEPTION.getMsg() + ": " + e.getMessage());
        }
        return resDto;
    }
}
